package com.cloudbench;

import static com.cloudbench.common.Constants.TIME_30_SECOND;



import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.cloudbench.common.wz.ProgressDialogFactory;
import com.cloudbench.logic.NodeService;
import com.cloudbench.util.NetworkUtil;
import com.cloudbench.util.WebGet;
import com.starter.Starter;
import com.cloudbench.util.*;


/*
 * 
 * Created by Oskar Hamren as part of the thesis 
 * work on mobile cloud computing, 2011-2012
 * 
 */


public class CloudBenchActivity extends Activity implements OnClickListener, Runnable {
	List<String> wordList = new ArrayList<String>();
	String textString = "";
    private ProgressBar progressBar;
    private TextView status;
    private TextView creator;
    private View startButtonView;
    //private View thirdButton;    
    private View forthButton;
    private File filen;
    private File downloadTempFile;
    private File tempSaveImage1;
    private File tempSaveImage2;
    private InputStream is;
    private String phoneModel;
    private String fingerPrint;
    private String phoneSDK;
    private String connectionInfo;
    
    private NodeInfoTask mNodeInfoTask;
    
    private ArrayList<String> mContentInput;
    private ArrayList<String> mContentOuput;
    /// its mmeeeee
    public String Re_val = "";
    // True Cloud Only
    // False Local Only
    public boolean gate = true;
    //
    // 1 = WIFI , 2= 2G , 3 = 3G
    public int WiSE_Tech = 1;
    public long tStart;
    public long tEnd;
    
    
    public boolean only_option = false;
    /*
    private String listSorterTest = "hang ten";
    private String primeCalcTest = "nada surf";
    private String imageTransformTest = "bro";
    */
    
    @Override
    public void onCreate(Bundle savedInstanceState) {  	        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        startButtonView = findViewById(R.id.button1);
        startButtonView.setOnClickListener(this);
       
//        progressBar = (ProgressBar) findViewById(R.id.progressBar);
//        status = (TextView) findViewById(R.id.status);  
//        creator = (TextView) findViewById(R.id.textView1);        
//        forthButton = findViewById(R.id.button4);
//        forthButton.setOnClickListener(this);
        
        //thirdButton = findViewById(R.id.button3);
        //thirdButton.setOnClickListener(this);

//        startButtonView.setVisibility(View.INVISIBLE);
//        forthButton.setVisibility(View.INVISIBLE);
//        creator.setVisibility(View.INVISIBLE);
        
//        new Thread(new Runnable() {
//            public void run() {
//            	handler.sendEmptyMessage(1);
//                gatherInfo();
//        		handler.sendEmptyMessage(2);
//                loadTextFile();
//        		handler.sendEmptyMessage(3);
//                loadImageFile();
//        		handler.sendEmptyMessage(4);
//            }
//            
//            private Handler handler = new Handler() {
//
//                @Override
//                public void handleMessage(Message msg) {
//                    switch (msg.what) {
//        	            case 1:
//        	            	status.setText(R.string.loading1);  
//        	            	progressBar.setProgress(25);
//        	                break;
//                    
//        	            case 2:
//        	                status.setText(R.string.loading2);  
//        	            	progressBar.setProgress(50);
//        	                break;     
//        	                
//        	            case 3:
//        	                status.setText(R.string.loading3);  
//        	            	progressBar.setProgress(75);
//        	                break; 	 
//        	                
//        	            case 4:
//        	                status.setText(R.string.loading4);  
//        	            	progressBar.setProgress(100);
//                        	startButtonView.setVisibility(View.VISIBLE);
//                        	forthButton.setVisibility(View.VISIBLE);
//                        	creator.setVisibility(View.VISIBLE);
//                            progressBar.setVisibility(ProgressBar.INVISIBLE);
//                            progressBar.setProgress(0);
//                            status.setVisibility(View.INVISIBLE);
//        	                break;     
//                        }
//                    }
//            	};        	
//          }).start();            
    }
    
    public Context ctx() {
    	return this;
    }
    	  
	private void gatherInfo() {
		this.phoneModel = android.os.Build.MODEL;
		this.phoneSDK = android.os.Build.VERSION.SDK;
		
		this.fingerPrint = phoneFingerPrint();
		this.connectionInfo = phoneConnection();

	}
	
	private String phoneConnection() {
		ConnectivityManager mConnectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		TelephonyManager mTelephony = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		
		NetworkInfo info = mConnectivity.getActiveNetworkInfo();
		if (info == null || !mConnectivity.getBackgroundDataSetting()) {
			return "NetworkError: Network == null ?";
		} else {
		
			int netType = info.getType();
			int netSubtype = info.getSubtype();
			if (netType == ConnectivityManager.TYPE_WIFI) {
				return "WIFI: " + netType;
			} else if (netType == ConnectivityManager.TYPE_MOBILE && netSubtype == TelephonyManager.NETWORK_TYPE_UMTS && !mTelephony.isNetworkRoaming()) {
				return "Phone: " + netType;
			} else {
				return "NetworkError2: Some other connection?";	
			}
		}	
	}
	
	private String phoneFingerPrint() {
	    final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
	    
	    //final String tmDevice, tmSerial, tmPhone, androidId;
	    final String tmDevice, tmSerial, androidId;
	    tmDevice = "" + tm.getDeviceId();
	    tmSerial = "" + tm.getSimSerialNumber();
	    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

	    UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
	   return deviceUuid.toString();
	}
    
	private void loadTextFile() {
        InputStream is;
        
		try {
			is = getAssets().open("text.txt");

	        BufferedReader br = new BufferedReader(new InputStreamReader(is));
	        String line = null;
	        while ((line = br.readLine()) != null) {
	        	this.wordList.add(line); 
	        	this.textString += line + " ";
	        }
	        br.close();
	        Collections.shuffle(this.wordList);
	        //this.listSorterTest = this.wordList.get(200) + " - " + this.wordList.get(201);
        	
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}

	private void loadImageFile() {
		try {
			this.is = getAssets().open("computer.jpg");
			
			File root = Environment.getExternalStorageDirectory();
			
            this.filen = new File(root, "computer1.jpg");
            this.filen.createNewFile();
            
            this.downloadTempFile = new File(root, "computer2.jpg");
            this.downloadTempFile.createNewFile();
            
            this.tempSaveImage1 = new File(root, "computer3.jpg");
            this.tempSaveImage1.createNewFile();
            
            this.tempSaveImage2 = new File(root, "computer4.jpg");
            this.tempSaveImage2.createNewFile();

            OutputStream out = new FileOutputStream(filen);
            byte buf[] = new byte[1024];
            int len;
            while((len = is.read(buf)) > 0) {
            	out.write(buf,0,len);
            }
            
            this.downloadTempFile.deleteOnExit();
            this.filen.deleteOnExit();
            this.tempSaveImage1.deleteOnExit();
            this.tempSaveImage1.deleteOnExit();
            
            out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}

	@Override
	public void onClick(View v) {
        switch(v.getId()){
        case R.id.button1:
        	
			startButtonView.setVisibility(View.INVISIBLE);
//			forthButton.setVisibility(View.INVISIBLE);
//			creator.setVisibility(View.INVISIBLE);
//			status.setText(R.string.start);
//			progressBar.setVisibility(ProgressBar.VISIBLE);
//			progressBar.setProgress(0);
//			status.setVisibility(View.VISIBLE);
			
//			for(int ii = 0 ;  ii < 4 ;  ii++){
			
		///////////
			 tStart = System.currentTimeMillis();
			Node nA=new Node(10,999);
			Node nB=new Node(20,99000);
			Node nC=new Node(30,150);
			Node nD=new Node(40,55300);
			Node nE=new Node(50,260);
			Node nF=new Node(60,17930);
			Node nG= new Node(80, 101000);

			//Create the graph, add nodes, create edges between nodes
			Graph g=new Graph();
			g.addNode(nA);
			g.addNode(nB);
			g.addNode(nC);
			g.addNode(nD);
			g.addNode(nE);
			g.addNode(nF);
			g.addNode(nG);
			
			g.setRootNode(nA);
			
			g.connectNode(nA,nB);
			g.connectNode(nA,nC);
			g.connectNode(nA,nD);
			
			g.connectNode(nB,nE);
			g.connectNode(nB,nF);
			g.connectNode(nC,nF);
			g.connectNode(nF, nG);
			System.out.println("\nBFS Traversal of a tree is ------------->");
			ArrayList<String> Insert_al = new ArrayList<String>();
			Insert_al = g.bfs();
			String request_data = g.First_Algor(Insert_al);
			
			
			
//		    String cmd = "adb shell dumpsys cpuinfo";
//		    String cmdreturn = "";
//		    Runtime run = Runtime.getRuntime();
//		    Process pr = run.exec(cmd);
//		    pr.waitFor();
//		    BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
//		    while ((line=buf.readLine())!=null) {
//		         System.out.println(cmdreturn);
//		    }
		    

		//	for(int jj = 0 ; jj < Insert_al.size() ; jj++){
			//	String content = Insert_al.get(jj); // this is for single execution
				//Log.d(String.valueOf(jj), String.valueOf(Insert_al.size()));
			
			if(only_option){
				String guestbookName = "default"; // this is for single execution
				//mNodeInfoTask = new NodeInfoTask(ctx(), content, guestbookName); // this is for single exectuion
			
				mNodeInfoTask = new NodeInfoTask(ctx(), request_data, guestbookName); 
		    	mNodeInfoTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");  // this is for single exectuion
			}
			else{
				System.out.println("Local Mode");
				String TaskID = "";
				String Amount_of_Task = "";
				String []RequestedTasks  =  request_data.split(":");
				Random random = new Random(); 
				DecimalFormat df = new DecimalFormat("#.###");
				String Returning_Result = null;
				double y = 0.0;
	            for(int i = 0 ; i < RequestedTasks.length ; i++){
	            	String [] IDandTask = RequestedTasks[i].split(";");
	            	TaskID = IDandTask[0];
	            	Amount_of_Task = IDandTask[1];
	              	int counter = Integer.parseInt(Amount_of_Task);
	              	
	              	for(int ii = 1 ; ii <= counter; ii ++ )
	              	{
	              	       double z  =  random.nextInt(800)+1;
	              	       double mu    =  random.nextInt(500)+1;
	              	       double sigma =   random.nextInt(900)+1;
	              	   //  Result += Phi(z, mu, sigma)+":";
	              	  //     System.out.println("1: " + Phi(z, mu, sigma));
	              	        y += Phi(z);
	              	      // System.out.println("2: "+ PhiInverse(y));
	              	}
	              //	System.out.println("Total Phi " +  y + " Counter "  + counter );
	              	y /= counter;
	              	
	              	 if(Returning_Result==null){
	              		
	                 	Returning_Result = TaskID +";"+ df.format(y);
	                 }
	                 else{
	                	df.format(y);
	                 	Returning_Result = Returning_Result+":" + TaskID +";"+ df.format(y);
	                 }
	            }
	            String result = Returning_Result;
	            String [] each_task = result.split(":");
		        System.out.println("Result packets from local: " + result);
		        for(int i = 0 ; i < each_task.length  ; i++){
		        	String [] id_result = each_task[i].split(";");
		        	System.out.println("Task ID: " + id_result[0]  + " AVG GUS VAL " + id_result[1]);
		        }
//		        String[] temp = each_task[each_task.length-1].split(";");
//		        String whatever = temp[1];
//		        whatever = whatever.replaceAll("\\s+","");
//		        int temp_value = Integer.parseInt(whatever);       
		        
//		        System.out.println("Incomming data packet Size(bytes): " + (182 + result.length()));
//		        System.out.println("Requesting data packet size(byte): " + (425 + temp_value));

//		        double Incom_value = ((184 +  result.length())*0.07) + (elapsedSeconds*0.05);
//		        double Outcom_value = ((425 +temp_value )*0.07) + (elapsedSeconds *0.05);
//		        System.out.println("WIFI COMM COST Incomming: "+ Incom_value + " J");
//		        System.out.println("WIFI COMM COST Request : "+ Outcom_value + " J");
		        tEnd = System.currentTimeMillis();
		    	long tDelta = tEnd - tStart;
		      	double elapsedSeconds = tDelta / 1000.0;
		        System.out.println("Time Cost: " +  elapsedSeconds);
			}
						 
		    	
		    	
		    	//	System.out.println(NodeService.results);
		    	///Log.d("Ok Real Done", Re_val);
		//	}
			//)

			
			
			
			// Multiple Calls
//			mContentInput = new ArrayList<String>(); // this is for mul
//			mContentInput.add("1:213");// this is for mul
//			mContentInput.add("2:341");// this is for mul
//			mContentInput.add("3:123");// this is for mul
//			String guestbookName = "default"; // this is for single execution
//			mNodeInfoTask = new NodeInfoTask(ctx(), mContentInput, guestbookName); // this is for mul
//			
//			mNodeInfoTask.execute();// this is for mul
			 
//			new Thread(this).start();
			

            /*
        	Toast toast1;
        	toast1 = Toast.makeText(this, "dude", Toast.LENGTH_LONG);
        	toast1.show();
        	*/
        break;
        
		/*  
        case R.id.button3:
        	status.setVisibility(View.VISIBLE);
			status.setText(this.listSorterTest + "&" + this.primeCalcTest + "&" + this.imageTransformTest + "&" + this.wordList.size() + "&" + this.connectionInfo + "&" + this.phoneSDK);       
        break;
        */
        
        case R.id.button4:
        	this.finish();
    	break;        
        }
	}
	
	///////////////////////
	
    public static double phi(double x) {
        return Math.exp(-x*x / 2) / Math.sqrt(2 * Math.PI);
    }
    public static double phi(double x, double mu, double sigma) {
        return phi((x - mu) / sigma) / sigma;
    }

    // return Phi(z) = standard Gaussian cdf using Taylor approximation
    public static double Phi(double z) {
        if (z < -8.0) return 0.0;
        if (z >  8.0) return 1.0;
        double sum = 0.0, term = z;
        for (int i = 3; sum + term != sum; i += 2) {
            sum  = sum + term;
            term = term * z * z / i;
        }
        return 0.5 + sum * phi(z);
    }

    // return Phi(z, mu, sigma) = Gaussian cdf with mean mu and stddev sigma
    public static double Phi(double z, double mu, double sigma) {
        return Phi((z - mu) / sigma);
    } 

    // Compute z such that Phi(z) = y via bisection search
    public static double PhiInverse(double y) {
        return PhiInverse(y, .00000001, -8, 8);
    } 

    // bisection search
    private static double PhiInverse(double y, double delta, double lo, double hi) {
        double mid = lo + (hi - lo) / 2;
        if (hi - lo < delta) return mid;
        if (Phi(mid) > y) return PhiInverse(y, delta, lo, mid);
        else              return PhiInverse(y, delta, mid, hi);
    }
    public void run() {
    	Starter start = new Starter();

		handler.sendEmptyMessage(16);
    	start.dataSaverInit();
    	start.savePhoneInfo(this.phoneModel, this.fingerPrint, this.phoneSDK, this.connectionInfo);
        
		start.downloadUploadSpeed(this.filen, this.downloadTempFile);
		handler.sendEmptyMessage(32);
        
		// this.primeCalcTest = start.primeCalc();
	//	start.primeCalc(20);
		handler.sendEmptyMessage(48);
    	
		// this.listSorterTest = start.listSorter(this.wordList, this.textString);
		start.listSorter(this.wordList, this.textString);
		handler.sendEmptyMessage(66);

		// this.imageTransformTest = start.imageTran(this.is, this.filen, this.tempSaveImage1, this.tempSaveImage2);
		start.imageTran(this.is, this.filen, this.tempSaveImage1, this.tempSaveImage2);
		handler.sendEmptyMessage(84);

		start.dataSaverFinnish();
		handler.sendEmptyMessage(100);
    	
		handler.sendEmptyMessage(101);
    }
    
    private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
	            case 16:
	                status.setText(R.string.start);  
	            	progressBar.setProgress(16);
	                break;
            
	            case 32:
	                status.setText(R.string.test1);  
	            	progressBar.setProgress(32);
	                break;     
	                
	            case 48:
	                status.setText(R.string.test2);  
	            	progressBar.setProgress(48);
	                break; 	 
	                
	            case 66:
	                status.setText(R.string.test3);  
	            	progressBar.setProgress(66);
	                break;     
	                
	            case 84:
	                status.setText(R.string.test4);  
	            	progressBar.setProgress(84);
	                break; 	                
	                
                case 100:
                    status.setText(R.string.send); 
	            	progressBar.setProgress(100);
                    break;
                    
                case 101:
                	startButtonView.setVisibility(View.VISIBLE);
                	forthButton.setVisibility(View.VISIBLE);
                    progressBar.setVisibility(ProgressBar.INVISIBLE);
                    creator.setVisibility(View.VISIBLE);
                    progressBar.setProgress(0);
                
                    try {
                    	Thread.sleep(2000);
                    } catch (InterruptedException e) {
                    	e.printStackTrace();
                    }

                    status.setVisibility(View.INVISIBLE);
                    break;
                }
            }
    	};
    	

    	/**
    	 * 
    	 * @Author : Daniel Han(original author : justin)
    	 * @Date : Aug 30, 2013
    	 * @Version : 1.0.0
    	 */
    	private class NodeInfoTask extends AsyncTask<String, Integer, String> {
    		private final String TNAME = NodeInfoTask.class.getSimpleName();
    		
    		// Input 
    		private Context c = null;
    		private String content;
    		private ArrayList<String> contentArray;
    		private String guestbookName;
    		
    		// Output

    	//	private ProgressDialog pd;
    		
    		public NodeInfoTask(Context c) {
    			this.c = c;
    		}

    		public NodeInfoTask(Context c, String content, String guestbookName) {
    			this.c = c;
    			this.content = content;
    			this.guestbookName = guestbookName;
    		}

    		public NodeInfoTask(Context c, ArrayList<String> contentArray, String guestbookName) {
    			this.c = c;
    			this.contentArray = contentArray;
    			this.guestbookName = guestbookName;
    		}

    		@Override
    		protected void onPreExecute() {
    			try {
//                    pd = ProgressDialogFactory.create(ctx(), "", getString(R.string.loading_default), false);
//                    if (pd != null) {
//                            pd.show();
//                    }
            }  catch (Exception e) {
                    
            }
    			super.onPreExecute();
    		}
    		
    		@Override
    		protected String doInBackground(String... params) {
    			if(!NetworkUtil.isAvailable(c))
    				return null;
    			
    			try {
//    				for(int i = 0; i < contentArray.size()-1; i++) {
//    					String contentItem = contentArray.get(i);
//    					String result = NodeService.newInstance().getStringContent(c, contentItem, guestbookName, TIME_30_SECOND);
//    					System.out.println("Result " +  result);
//    					mContentOuput.add(result);
//    					
//    				}
//    				
    		return NodeService.newInstance().getStringContent(c, content, guestbookName, TIME_30_SECOND);
    			} catch(Exception e) {
					Log.e(TNAME, e.getMessage().toString());
    			}

    			return null;
    		}

    		@Override
    		// Bob
    		protected void onPostExecute(String result) {	
    			try {
					
    				
    				// Failed
					if( result == null) {
    					return;
    				}

					//Success
				       tEnd = System.currentTimeMillis();
				    	long tDelta = tEnd - tStart;
				      	double elapsedSeconds = tDelta / 1000.0;
				        
				        /// Temp display function here 
				        String [] each_task = result.split(":");
				        System.out.println("Result packets from cloud: " + result);
				        for(int i = 0 ; i < each_task.length -1 ; i++){
				        	String [] id_result = each_task[i].split(";");
				        	System.out.println("Task ID: " + id_result[0]  + " AVG GUS VAL " + id_result[1]);
				        }
				        String[] temp = each_task[each_task.length-1].split(";");
				        String whatever = temp[1];
				        whatever = whatever.replaceAll("\\s+","");
				        int temp_value = Integer.parseInt(whatever);       
				        
				        System.out.println("Incomming data packet Size(bytes): " + (182 + result.length()));
				        System.out.println("Requesting data packet size(byte): " + (425 + temp_value));
				        double Incom_value = ((184 +  result.length())*0.07) + (elapsedSeconds*0.05);
				        double Outcom_value = ((425 +temp_value )*0.07) + (elapsedSeconds *0.05);
				        System.out.println("WIFI COMM COST Incomming: "+ Incom_value + " J");
				        System.out.println("WIFI COMM COST Request : "+ Outcom_value + " J");
				        System.out.println("Time Cost: " +  elapsedSeconds);
				        Log.d(TNAME,result);
					
    			} catch(Exception e) {
					Log.e(TNAME, e.getMessage().toString());
    			}
    			
    		}
    		
    	}    	 
}